{
  "openapi": "3.1.0",
  "info": {
    "title": "Cloud Storage Local API",
    "description": "Gestiona los archivos, las subidas, las eliminaciones y las etiquetas de archivo del almacenamiento en la nube de MoreLogin a través de la MoreLogin Local API.\n\n**URL base**: `http://127.0.0.1:40000`\n\nLas rutas de la Local API usan el prefijo `/api`.\n",
    "version": "2026-09-05"
  },
  "servers": [
    {
      "url": "http://127.0.0.1:40000"
    }
  ],
  "tags": [
    {
      "name": "Cloud Storage",
      "description": "Consultar cuota y uso del almacenamiento"
    },
    {
      "name": "Cloud Storage Files",
      "description": "Consultar, subir y eliminar archivos de almacenamiento en la nube"
    },
    {
      "name": "Cloud Storage File Tags",
      "description": "Gestionar etiquetas asociadas a archivos de almacenamiento en la nube"
    }
  ],
  "x-tagGroups": [
    {
      "name": "Cloud Storage",
      "tags": [
        "Cloud Storage",
        "Cloud Storage Files",
        "Cloud Storage File Tags"
      ]
    }
  ],
  "paths": {
    "/api/cloudstorage/info": {
      "get": {
        "summary": "Consultar información del almacenamiento en la nube",
        "description": "Devuelve la cuota de Cloud Storage del equipo y el uso actual.\n- **Requisitos previos**: el equipo debe tener ya un registro de Cloud Storage. **Un equipo que nunca ha tenido Cloud Storage aprovisionado recibe un error, no una lectura de capacidad cero**: el registro se crea al comprar almacenamiento, no de forma diferida por esta llamada.\n- **Efecto**: ninguno. Solo lectura. Es seguro reintentar con retroceso acotado.\n- **Unidades**: `capacity` y `usedCapacity` son recuentos de bytes.\n- **Precisión**: `usedCapacity` es un contador acumulado que se mantiene al subir y al eliminar, no una suma en vivo sobre la tabla de archivos, así que puede desviarse del total de `fileSize` en `/cloudstorage/file/page`.\n- **Valores**: `capacityStatus` es `1` solo cuando una cuota positiva está totalmente consumida; `isExpired` compara la fecha de caducidad con el momento actual. Los archivos cuya subida nunca se confirmó no cuentan para `usedCapacity`.\n\nErrores de negocio documentados: `39001`. Consulte [Error Codes](../Getting%20Started/error-codes.md) para el significado de cada código. Cualquier operación puede devolver además los códigos comunes.",
        "operationId": "queryCloudStorageInfoLocal",
        "tags": [
          "Cloud Storage"
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/StorageInfoResponse"
          }
        }
      }
    },
    "/api/cloudstorage/file/page": {
      "post": {
        "summary": "Paginar archivos de almacenamiento en la nube",
        "description": "Lista los archivos de Cloud Storage, página a página.\n- **Efecto**: ninguno. Solo lectura. Es seguro reintentar con retroceso acotado.\n- **Visibilidad**: **solo se listan los archivos cuya subida se confirmó**: un archivo con una URL prefirmada que nunca se completó no aparece. Los miembros sin el permiso de todos los datos solo ven los archivos que subieron ellos.\n- **Filtrado**: `fileName` admite coincidencia parcial; `tagIds` es una coincidencia OR; los resultados se ordenan de más nuevo a más antiguo y ese orden no se puede cambiar.\n- **Advertencia**: una entrada de `tagInfo` puede ser null cuando una etiqueta se eliminó mientras seguía asignada al archivo.",
        "operationId": "pageCloudStorageFilesLocal",
        "tags": [
          "Cloud Storage Files"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FilePageRequest"
              },
              "example": {
                "pageNo": 1,
                "pageSize": 20,
                "fileName": "report",
                "tagIds": [
                  "1800000000000001"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/FilePageResponse"
          }
        }
      }
    },
    "/api/cloudstorage/upload/init": {
      "post": {
        "summary": "Solicitar por lotes URL de subida prefirmadas",
        "description": "Reserva registros de Cloud Storage y obtén URL de subida prefirmadas.\n- **Requisitos previos**: el equipo debe tener un registro de Cloud Storage y no puede estar caducado. Cada nombre base de archivo se limita a 60 caracteres y debe ser único tanto dentro de la petición como frente a todos los archivos existentes del equipo — **la comparación es sobre el nombre sin su extensión**, así que `a.png` choca con un `a.mp4` existente.\n- **Límites**: como máximo 100 subidas pueden estar sin confirmar a la vez en todo el equipo.\n- **Efecto**: inserta un registro por nombre con estado de subida en curso y tamaño cero, y devuelve `{id, fileName, presignedUrl}` para cada uno.\n- **Cuota**: **aquí no se comprueba el espacio.** Se cobra al confirmar la subida, así que init puede tener éxito y complete fallar de todos modos por falta de espacio.\n- **Finalización**: sincrónica. **Cada URL prefirmada es válida durante una hora**; envía los bytes con `PUT` y después llama a `/cloudstorage/upload/complete`.\n\nErrores de negocio documentados: `39001`, `39037`, `39044`, `39045`, `39047`, `39050`, `39051`. Consulte [Error Codes](../Getting%20Started/error-codes.md) para el significado de cada código. Cualquier operación puede devolver además los códigos comunes.",
        "operationId": "batchRequestCloudStoragePresignedUploadUrlsLocal",
        "tags": [
          "Cloud Storage Files"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadInitRequest"
              },
              "example": {
                "fileNames": [
                  "example.jpg"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/UploadInitResponse"
          }
        }
      }
    },
    "/api/cloudstorage/upload/complete": {
      "post": {
        "summary": "Confirmar finalización de la subida",
        "description": "Confirma un archivo de Cloud Storage ya subido.\n- **Requisitos previos**: el registro del archivo debe pertenecer a tu equipo y el objeto debe estar ya en el almacenamiento: el servicio lee su ETag y su longitud para verificarlo. El tamaño debe ser mayor que 0 y menor de 2 GB.\n- **Efecto**: cobra la cuota de almacenamiento del equipo de forma atómica, y después marca el registro como subido y guarda el tamaño real. Hasta que esto no tiene éxito el archivo **no aparece en `/cloudstorage/file/page`** y sigue ocupando una de las 100 plazas pendientes.\n- **Si falla, el objeto subido se elimina.** Llamarlo demasiado pronto, por encima del límite de tamaño o sin espacio libre borra los bytes del almacenamiento y deja el registro sin confirmar. La recuperación es un `/cloudstorage/upload/init` nuevo y volver a subir, no reintentar esta llamada.\n- **Finalización**: sincrónica e idempotente una vez que ha tenido éxito: una segunda llamada devuelve el mismo archivo sin volver a cobrar cuota.\n- **Nota**: un registro que nunca se confirma se limpia automáticamente al cabo de 24 horas.\n\nErrores de negocio documentados: `39001`, `39011`, `39014`, `39041`, `39046`, `39047`. Consulte [Error Codes](../Getting%20Started/error-codes.md) para el significado de cada código. Cualquier operación puede devolver además los códigos comunes.",
        "operationId": "confirmCloudStorageUploadCompleteLocal",
        "tags": [
          "Cloud Storage Files"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadCompleteRequest"
              },
              "example": {
                "id": "1800000000000001"
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/UploadCompleteResponse"
          }
        }
      }
    },
    "/api/cloudstorage/file/delete/batch": {
      "post": {
        "summary": "Eliminar por lotes archivos de almacenamiento en la nube",
        "description": "Elimina archivos de Cloud Storage por identificador.\n- **Requisitos previos**: todos los identificadores deben resolverse dentro de tu equipo; **si uno solo no lo hace, el lote completo se rechaza y se revierte**, incluidos los identificadores que ya estaban eliminados.\n- **Efecto**: es un borrado lógico. La cuota se libera en la misma transacción y los objetos almacenados se eliminan en la medida de lo posible; un fallo del almacenamiento se registra pero no hace fallar la llamada, así que un objeto puede sobrevivir a su registro. Las asignaciones de etiquetas no se limpian.\n- **Finalización**: sincrónica. Confirma el espacio liberado con `/cloudstorage/info`.\n\nErrores de negocio documentados: `39011`. Consulte [Error Codes](../Getting%20Started/error-codes.md) para el significado de cada código. Cualquier operación puede devolver además los códigos comunes.",
        "operationId": "batchDeleteCloudStorageFilesLocal",
        "tags": [
          "Cloud Storage Files"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FileDeleteRequest"
              },
              "example": {
                "ids": [
                  "1800000000001001",
                  "1800000000001002"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/VoidDataResponse"
          }
        }
      }
    },
    "/api/cloudstorage/file/tag/set": {
      "post": {
        "summary": "Establecer etiquetas de archivo",
        "description": "Reemplaza las etiquetas de un archivo de Cloud Storage.\n- **Requisitos previos**: un `fileId` por llamada, y `tagIds` no puede estar vacío y debe referirse a etiquetas de Cloud Storage que pertenezcan a tu equipo. Las etiquetas de perfiles se rechazan.\n- **Efecto**: las etiquetas que no aparecen en la petición se quitan del archivo y las que faltan se añaden. **Aquí no hay forma de quitar todas las etiquetas** porque una lista vacía se rechaza.\n- **Finalización**: sincrónica e idempotente para el mismo cuerpo.\n\nErrores de negocio documentados: `39011`, `39048`, `39049`. Consulte [Error Codes](../Getting%20Started/error-codes.md) para el significado de cada código. Cualquier operación puede devolver además los códigos comunes.",
        "operationId": "setCloudStorageFileTagsLocal",
        "tags": [
          "Cloud Storage File Tags"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FileTagChangeRequest"
              },
              "example": {
                "fileId": "1800000000001001",
                "tagIds": [
                  "1800000000000101",
                  "1800000000000102"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/VoidDataResponse"
          }
        }
      }
    },
    "/api/cloudstorage/file/tag/add": {
      "post": {
        "summary": "Añadir etiquetas de archivo",
        "description": "Añade etiquetas a un archivo de Cloud Storage sin quitar las existentes.\n- **Requisitos previos**: un `fileId` por llamada, y `tagIds` no puede estar vacío y debe referirse a etiquetas de Cloud Storage que pertenezcan a tu equipo.\n- **Efecto**: solo añade; las etiquetas existentes se mantienen. Usa la variante de reemplazo para sustituirlas.\n- **Finalización**: sincrónica e idempotente; añadir una etiqueta que el archivo ya tiene no cambia nada.\n\nErrores de negocio documentados: `39011`, `39048`, `39049`. Consulte [Error Codes](../Getting%20Started/error-codes.md) para el significado de cada código. Cualquier operación puede devolver además los códigos comunes.",
        "operationId": "addCloudStorageFileTagsLocal",
        "tags": [
          "Cloud Storage File Tags"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FileTagChangeRequest"
              },
              "example": {
                "fileId": "1800000000001001",
                "tagIds": [
                  "1800000000000103"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/VoidDataResponse"
          }
        }
      }
    },
    "/api/cloudstorage/file/tag/query": {
      "post": {
        "summary": "Consultar etiquetas de archivo",
        "description": "Devuelve las etiquetas asignadas a uno o varios archivos de Cloud Storage.\n- **Requisitos previos**: todos los `fileId` deben resolverse dentro de tu equipo; **un único identificador desconocido hace fallar toda la llamada** en lugar de devolver datos parciales.\n- **Efecto**: ninguno. Solo lectura. Es seguro reintentar con retroceso acotado.\n- **Advertencia**: `tagIds` se lee de las asignaciones mientras los detalles de las etiquetas vienen de las etiquetas vigentes, así que una etiqueta eliminada mientras seguía asignada aparece en `tagIds` sin entrada correspondiente en los detalles. Ambas listas pueden tener longitudes distintas.",
        "operationId": "queryCloudStorageFileTagsLocal",
        "tags": [
          "Cloud Storage File Tags"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FileTagQueryRequest"
              },
              "example": {
                "fileIds": [
                  "1800000000001001"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/FileTagsResponse"
          }
        }
      }
    },
    "/api/cloudstorage/tag/all": {
      "get": {
        "summary": "Consultar todas las etiquetas de archivo de Cloud Storage",
        "description": "Devuelve todas las etiquetas de archivo de Cloud Storage del equipo.\n- **Efecto**: ninguno. Solo lectura. Es seguro reintentar con retroceso acotado.\n- **Nota**: no está paginado y las etiquetas de Cloud Storage no tienen límite de cantidad en el servidor, así que la respuesta crece con el número de etiquetas que cree tu equipo.",
        "operationId": "queryAllCloudStorageFileTagsLocal",
        "tags": [
          "Cloud Storage File Tags"
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/TagListResponse"
          }
        }
      }
    },
    "/api/cloudstorage/tag/create": {
      "post": {
        "summary": "Crear etiqueta de archivo de Cloud Storage",
        "description": "Crea una etiqueta de archivo de Cloud Storage.\n- **Requisitos previos**: `tagName` no puede estar vacío.\n- **Efecto**: crea la etiqueta con un color elegido de una paleta fija. **No se comprueba si el nombre está duplicado y no hay límite de cantidad**, así que repetir la llamada crea una segunda etiqueta con el mismo nombre.\n- **Finalización**: sincrónica; la respuesta lleva la etiqueta nueva.",
        "operationId": "createCloudStorageFileTagLocal",
        "tags": [
          "Cloud Storage File Tags"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TagCreateRequest"
              },
              "example": {
                "tagName": "Invoice"
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/TagResponse"
          }
        }
      }
    },
    "/api/cloudstorage/tag/edit": {
      "post": {
        "summary": "Editar etiqueta de archivo de Cloud Storage",
        "description": "Renombra una etiqueta de archivo de Cloud Storage.\n- **Requisitos previos**: la etiqueta debe existir en tu equipo y ser una etiqueta de Cloud Storage.\n- **Efecto**: solo cambia el nombre; se conservan el color y todas las asignaciones existentes, así que los archivos muestran el nombre nuevo de inmediato.\n- **Finalización**: sincrónica. Sin bloqueo optimista: los renombrados simultáneos se resuelven con la última escritura.",
        "operationId": "editCloudStorageFileTagLocal",
        "tags": [
          "Cloud Storage File Tags"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TagEditRequest"
              },
              "example": {
                "id": "1800000000000101",
                "tagName": "Invoice 2026"
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/BooleanDataResponse"
          }
        }
      }
    },
    "/api/cloudstorage/tag/delete/batch": {
      "post": {
        "summary": "Eliminar etiquetas de archivo de Cloud Storage",
        "description": "Elimina etiquetas de archivo de Cloud Storage.\n- **Requisitos previos**: todos los identificadores deben ser etiquetas de Cloud Storage de tu equipo; **un único identificador inválido hace fallar el lote completo**.\n- **Efecto**: las etiquetas se eliminan pero **sus asignaciones a archivos no se limpian**. Cabe esperar dos consecuencias: `/cloudstorage/file/tag/query` sigue devolviendo el identificador de la etiqueta eliminada sin detalle correspondiente, y `tagInfo` en `/cloudstorage/file/page` puede contener entradas null. Filtrar archivos por el identificador de una etiqueta eliminada no devuelve nada.\n- **Finalización**: sincrónica, y no está envuelta en una transacción.",
        "operationId": "deleteCloudStorageFileTagsLocal",
        "tags": [
          "Cloud Storage File Tags"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TagDeleteRequest"
              },
              "example": {
                "ids": [
                  "1800000000000101"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/BooleanDataResponse"
          }
        }
      }
    }
  },
  "security": [],
  "components": {
    "schemas": {
      "ApiResponseBase": {
        "type": "object",
        "properties": {
          "code": {
            "type": "integer",
            "description": "Código de resultado. `0` significa correcto; otros códigos indican excepciones.",
            "example": 0
          },
          "msg": {
            "type": [
              "string",
              "null"
            ],
            "description": "Mensaje de error.",
            "example": null
          },
          "requestId": {
            "type": "string",
            "description": "ID de la petición de la operación. Este campo puede estar presente cuando la petición pasa por la puerta de enlace de la API.",
            "example": "1d4f3ea968664593860b94b35d4ebf5e"
          }
        },
        "required": [
          "code",
          "msg"
        ]
      },
      "StorageInfo": {
        "type": "object",
        "properties": {
          "capacity": {
            "type": "string",
            "description": "Capacidad total de almacenamiento en la nube en bytes.",
            "example": "10737418240"
          },
          "usedCapacity": {
            "type": "string",
            "description": "Capacidad de almacenamiento en la nube usada en bytes.",
            "example": "536870912"
          },
          "expireDate": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$",
            "description": "Fecha de caducidad del almacenamiento en la nube."
          },
          "capacityStatus": {
            "type": "integer",
            "description": "Estado de la capacidad: 0 = normal, 1 = llena.",
            "example": 0
          },
          "isExpired": {
            "type": "boolean",
            "description": "Si el plan de suscripción ha caducado.",
            "example": false
          }
        }
      },
      "FilePageRequest": {
        "type": "object",
        "properties": {
          "pageNo": {
            "type": "integer",
            "description": "Número de la página actual, empezando por 1. Por defecto es 1.",
            "minimum": 1,
            "default": 1,
            "example": 1
          },
          "pageSize": {
            "type": "integer",
            "description": "Número de elementos por página. Por defecto es 10.",
            "minimum": 1,
            "default": 10,
            "example": 20
          },
          "fileName": {
            "type": "string",
            "description": "Palabra clave del nombre de archivo para búsqueda difusa.",
            "example": "report"
          },
          "tagIds": {
            "type": "array",
            "description": "Filtra los archivos por ID de etiqueta.",
            "items": {
              "type": "string"
            },
            "example": [
              "1800000000000101"
            ]
          },
          "fileType": {
            "type": "integer",
            "description": "Filtro por tipo de archivo: 0 = imagen, 1 = vídeo, 2 = aplicación, 3 = audio, 4 = documento, 5 = otro.",
            "example": 0
          },
          "fileIds": {
            "type": "array",
            "description": "Filtra los archivos por ID de archivo.",
            "items": {
              "type": "string"
            },
            "example": [
              "1800000000001001"
            ]
          }
        }
      },
      "TagInfo": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID de la etiqueta.",
            "example": "1800000000000101"
          },
          "tagSource": {
            "type": "string",
            "description": "Origen de la etiqueta, por ejemplo ENV, PROXY.",
            "example": "ENV"
          },
          "tagName": {
            "type": "string",
            "description": "Nombre de la etiqueta.",
            "example": "Invoice"
          },
          "tagType": {
            "type": "string",
            "description": "Tipo de etiqueta: TAG o GROUP.",
            "example": "TAG"
          },
          "tagIcon": {
            "type": "string",
            "description": "Icono de la etiqueta.",
            "example": ""
          }
        }
      },
      "CloudStorageFile": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID del archivo de almacenamiento en la nube.",
            "example": "1800000000001001"
          },
          "fileName": {
            "type": "string",
            "description": "Nombre del archivo (sin extensión).",
            "example": "example"
          },
          "fileExt": {
            "type": "string",
            "description": "Extensión del archivo.",
            "example": "jpg"
          },
          "fileSize": {
            "type": "string",
            "description": "Tamaño del archivo en bytes.",
            "example": "204800"
          },
          "fileType": {
            "type": "integer",
            "description": "Tipo de archivo: 0 = imagen, 1 = vídeo, 2 = aplicación, 3 = audio, 4 = documento, 5 = otro.",
            "example": 0
          },
          "tagInfo": {
            "type": "array",
            "description": "Detalles de las etiquetas asociadas al archivo.",
            "items": {
              "$ref": "#/components/schemas/TagInfo"
            }
          },
          "createDate": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$",
            "description": "Fecha de subida."
          },
          "updateDate": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$",
            "description": "Fecha de actualización."
          }
        }
      },
      "FilePageData": {
        "type": "object",
        "properties": {
          "current": {
            "type": "string",
            "example": "1"
          },
          "pages": {
            "type": "string",
            "example": "7"
          },
          "total": {
            "type": "string",
            "example": "128"
          },
          "dataList": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CloudStorageFile"
            }
          }
        },
        "required": [
          "current",
          "pages",
          "total",
          "dataList"
        ]
      },
      "UploadInitRequest": {
        "type": "object",
        "properties": {
          "fileNames": {
            "type": "array",
            "minItems": 1,
            "description": "Lista de nombres de archivo que se subirán (con extensión), por ejemplo photo.jpg, video.mp4.",
            "items": {
              "type": "string"
            },
            "example": [
              "photo.jpg",
              "video.mp4"
            ]
          }
        },
        "required": [
          "fileNames"
        ]
      },
      "UploadInitResult": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID del archivo de almacenamiento en la nube.",
            "example": "1800000000000001"
          },
          "fileName": {
            "type": "string",
            "description": "Nombre del archivo (con extensión).",
            "example": "photo.jpg"
          },
          "presignedUrl": {
            "type": "string",
            "description": "URL prefirmada de S3 para subir. Usa HTTPS PUT para subir el contenido del archivo.",
            "example": "https://example.com/presigned-upload-url"
          }
        }
      },
      "UploadCompleteRequest": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID del archivo de Cloud Storage devuelto por la API de URL prefirmada de subida.",
            "example": "1800000000000001"
          }
        },
        "required": [
          "id"
        ]
      },
      "FileDeleteRequest": {
        "type": "object",
        "properties": {
          "ids": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string"
            },
            "description": "ID de los archivos de Cloud Storage que se eliminarán.",
            "example": [
              "1800000000001001",
              "1800000000001002"
            ]
          }
        },
        "required": [
          "ids"
        ]
      },
      "FileTagChangeRequest": {
        "type": "object",
        "properties": {
          "fileId": {
            "type": "string",
            "description": "ID del archivo de almacenamiento en la nube.",
            "example": "1800000000001001"
          },
          "tagIds": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string"
            },
            "description": "ID de etiquetas.",
            "example": [
              "1800000000000101",
              "1800000000000102"
            ]
          }
        },
        "required": [
          "fileId",
          "tagIds"
        ]
      },
      "FileTagQueryRequest": {
        "type": "object",
        "properties": {
          "fileIds": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string"
            },
            "description": "ID de archivos de Cloud Storage.",
            "example": [
              "1800000000001001"
            ]
          }
        },
        "required": [
          "fileIds"
        ]
      },
      "FileTagResultData": {
        "type": "object",
        "properties": {
          "fileId": {
            "type": "string",
            "description": "ID del archivo de almacenamiento en la nube.",
            "example": "1800000000001001"
          },
          "tagIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "ID de las etiquetas asociadas al archivo.",
            "example": [
              "1800000000000101"
            ]
          },
          "tagInfo": {
            "type": "array",
            "description": "Detalles de las etiquetas.",
            "items": {
              "$ref": "#/components/schemas/TagInfo"
            }
          }
        }
      },
      "TagCreateRequest": {
        "type": "object",
        "properties": {
          "tagName": {
            "type": "string",
            "description": "Nombre de la etiqueta.",
            "example": "Invoice"
          }
        },
        "required": [
          "tagName"
        ]
      },
      "TagEditRequest": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "ID de la etiqueta.",
            "example": "1800000000000101"
          },
          "tagName": {
            "type": "string",
            "description": "Nombre de la etiqueta.",
            "example": "Invoice 2026"
          }
        },
        "required": [
          "id",
          "tagName"
        ]
      },
      "TagDeleteRequest": {
        "type": "object",
        "properties": {
          "ids": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string"
            },
            "description": "ID de las etiquetas que se eliminarán.",
            "example": [
              "1800000000000101"
            ]
          }
        },
        "required": [
          "ids"
        ]
      }
    },
    "responses": {
      "StorageInfoResponse": {
        "description": "Correcto",
        "content": {
          "application/json": {
            "schema": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/ApiResponseBase"
                },
                {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/StorageInfo"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              ]
            }
          }
        }
      },
      "FilePageResponse": {
        "description": "Correcto",
        "content": {
          "application/json": {
            "schema": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/ApiResponseBase"
                },
                {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/FilePageData"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              ]
            }
          }
        }
      },
      "UploadInitResponse": {
        "description": "Correcto",
        "content": {
          "application/json": {
            "schema": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/ApiResponseBase"
                },
                {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/UploadInitResult"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              ]
            }
          }
        }
      },
      "UploadCompleteResponse": {
        "description": "Correcto",
        "content": {
          "application/json": {
            "schema": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/ApiResponseBase"
                },
                {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/CloudStorageFile"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              ]
            }
          }
        }
      },
      "VoidDataResponse": {
        "description": "Correcto",
        "content": {
          "application/json": {
            "schema": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/ApiResponseBase"
                },
                {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "null",
                      "example": null
                    }
                  }
                }
              ]
            }
          }
        }
      },
      "FileTagsResponse": {
        "description": "Correcto",
        "content": {
          "application/json": {
            "schema": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/ApiResponseBase"
                },
                {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/FileTagResultData"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              ]
            }
          }
        }
      },
      "TagListResponse": {
        "description": "Correcto",
        "content": {
          "application/json": {
            "schema": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/ApiResponseBase"
                },
                {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TagInfo"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              ]
            }
          }
        }
      },
      "TagResponse": {
        "description": "Correcto",
        "content": {
          "application/json": {
            "schema": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/ApiResponseBase"
                },
                {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/TagInfo"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              ]
            }
          }
        }
      },
      "BooleanDataResponse": {
        "description": "Correcto",
        "content": {
          "application/json": {
            "schema": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/ApiResponseBase"
                },
                {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "boolean",
                      "example": true
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              ]
            }
          }
        }
      }
    }
  }
}